--
-- user_app.vhd - user application code
--
-- SYNTHESIZABLE
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_misc.all;
use ieee.std_logic_arith.all;

library work;
--use work.memif.all;
use work.admxrc5t2_common.all;
use work.user_defs.all;

entity user_app is
    port(
        rst           : in    std_logic;   -- Reset from memory clock domain
        clk           : in    std_logic;   -- Clock from memory clock domain
        -- To/from local bus interface (32 x 64-bit register)
        reg_in        : in    std_logic_vector(63 downto 0);
        reg_wr        : in    std_logic_vector(255 downto 0); -- 256 bwe
        reg_out       : out   std_logic_vector(2047 downto 0); -- 256 bytes
        -- MGT interface
        mgt_clk       : in    std_logic;
        mgt_rdy       : in    std_logic;
        mgt_txd       : out   mgt_data_t(3 downto 0);
        mgt_txk       : out   std_logic_vector(7 downto 0);
        mgt_rxd       : in    mgt_data_t(3 downto 0);
        mgt_rxk       : in    std_logic_vector(7 downto 0);
        mgt_aligned   : in    std_logic_vector(3 downto 0);
        -- To/from memory banks
        valid         : in    control_vector_t(max_num_bank - 1 downto 0);
        q             : in    data_vector_t(max_num_bank - 1 downto 0);
        qtag          : in    tag_vector_t(max_num_bank - 1 downto 0);
        ready         : in    control_vector_t(max_num_bank - 1 downto 0);
        req           : out   control_vector_t(max_num_bank - 1 downto 0);
        ce            : out   control_vector_t(max_num_bank - 1 downto 0);
        w             : out   control_vector_t(max_num_bank - 1 downto 0);
        a             : out   address_vector_t(max_num_bank - 1 downto 0);
        tag           : out   tag_vector_t(max_num_bank - 1 downto 0);
        d             : out   data_vector_t(max_num_bank - 1 downto 0);
        be            : out   be_vector_t(max_num_bank - 1 downto 0));
end entity;

architecture syn of user_app is

  COMPONENT pe_mc IS
    GENERIC (
    cores : integer := 10);
    PORT (
    debug : out std_logic_vector(31 downto 0);
    -- global interface
    clk   : in  std_logic;
    rst   : in  std_logic;
    en    : in  std_logic;
    -- parameter interface
    n     : in  std_logic_vector(31 downto 0);
    i_ini : in  std_logic_vector(31 downto 0);
    i_end : in  std_logic_vector(31 downto 0);
    eps   : in  std_logic_vector(31 downto 0);
    -- ram interface
    rdy   : in  std_logic;
    req   : out std_logic;
    vld   : in  std_logic;
    addr  : out std_logic_vector(31 downto 0);
    p_x   : in  std_logic_vector(31 downto 0);
    p_y   : in  std_logic_vector(31 downto 0);
    p_z   : in  std_logic_vector(31 downto 0);
    p_m   : in  std_logic_vector(31 downto 0);
    -- control interface
    start : in  std_logic;
    done  : out std_logic;
    i_cnt : out std_logic_vector(31 downto 0);
    fifo_r: in  std_logic;
    a_x   : out reg_data_t(cores-1 downto 0);
    a_y   : out reg_data_t(cores-1 downto 0);
    a_z   : out reg_data_t(cores-1 downto 0));
  END COMPONENT;

  signal debug    : std_logic_vector(31 downto 0);

  signal en       : std_logic;

  signal reg_n    : std_logic_vector(31 downto 0);
  signal reg_ini  : std_logic_vector(31 downto 0);
  signal reg_end  : std_logic_vector(31 downto 0);
  signal reg_eps  : std_logic_vector(31 downto 0);

  signal pe_read  : std_logic;
  signal p_x      : std_logic_vector(31 downto 0);
  signal p_y      : std_logic_vector(31 downto 0);
  signal p_z      : std_logic_vector(31 downto 0);
  signal p_m      : std_logic_vector(31 downto 0);

  signal start    : std_logic;
  signal done     : std_logic;
  signal i_cnt    : std_logic_vector(31 downto 0);
  signal fifo_r   : std_logic;
  signal a_x      : reg_data_t(10-1 downto 0);
  signal a_y      : reg_data_t(10-1 downto 0);
  signal a_z      : reg_data_t(10-1 downto 0);

begin

  -- disable SSRAM
  gen_dummy: for i in 1 to max_num_bank -1 generate
    req(i) <= '0';
    ce(i)  <= '0';
    w(i)   <= '0';
    a(i)   <= (others => '0');
    tag(i) <= (others => '0');
    d(i)   <= (others => '0');
    be(i)  <= (others => '0');
  end generate;

  -- enable SDRAM Bank 0
  w(0)   <= '0';
  tag(0) <= (others => '0');
  d(0)   <= (others => '0');
  be(0)  <= (others => '1');

  U_request: process (clk)
  begin
    if rising_edge(clk) then
      if start = '1' then
        req(0) <= '1';
      elsif done = '1' then
        req(0) <= '0';
      end if;
    end if;
  end process;
  ce(0)  <= pe_read; -- our pe will not issue command if not ready

  p_m <= q(0)(31 downto 0);
  p_x <= q(0)(63 downto 32);
  p_y <= q(0)(95 downto 64);
  p_z <= q(0)(127 downto 96);

  U_REG: process (clk)
    variable i : integer;
  begin
    if rising_edge(clk) then
      for i in 3 downto 0 loop
        if reg_wr(i+16) = '1' then
          reg_n(i*8+7 downto i*8) <= reg_in(i*8+7 downto i*8);
        end if;
      end loop;
      for i in 3 downto 0 loop
        if reg_wr(i+20) = '1' then
          reg_ini(i*8+7 downto i*8) <= reg_in(i*8+7 downto i*8);
        end if;
      end loop;
      for i in 3 downto 0 loop
        if reg_wr(i+24) = '1' then
          reg_end(i*8+7 downto i*8) <= reg_in(i*8+7 downto i*8);
        end if;
      end loop;
      for i in 3 downto 0 loop
        if reg_wr(i+28) = '1' then
          reg_eps(i*8+7 downto i*8) <= reg_in(i*8+7 downto i*8);
        end if;
      end loop;
    end if;
  end process;

  en <= not rst;
  start <= reg_in(0) and reg_wr(0);
  fifo_r <= reg_in(1) and reg_wr(0);
  U_pe_mc : pe_mc
    generic map (
      cores => 10)
    port map (
      debug  => debug  ,
      clk    => clk    ,
      rst    => rst    ,
      en     => en     ,

      n      => reg_n  ,
      i_ini  => reg_ini,
      i_end  => reg_end,
      eps    => reg_eps,

      rdy    => ready(0),
      req    => pe_read,
      vld    => valid(0),
      addr   => a(0)   ,
      p_x    => p_x    ,
      p_y    => p_y    ,
      p_z    => p_z    ,
      p_m    => p_m    ,

      start  => start  ,
      done   => done   ,
      fifo_r => fifo_r ,
      i_cnt  => i_cnt  ,
      a_x    => a_x    ,
      a_y    => a_y    ,
      a_z    => a_z    );

  reg_out(31  downto   0) <= i_cnt;
  U_REG_OUT: for core_id in 0 to 10-1 generate
    reg_out((core_id*3+2)*32-1  downto  (core_id*3+1)*32) <= a_x(core_id);
    reg_out((core_id*3+3)*32-1  downto  (core_id*3+2)*32) <= a_y(core_id);
    reg_out((core_id*3+4)*32-1  downto  (core_id*3+3)*32) <= a_z(core_id);
  end generate;
  reg_out((10*3+2)*32-1 downto (10*3+1)*32) <= debug;
  reg_out(2047 downto 11*3*32) <= (others=>'0');

  -- MGT
  mgt_txd(0) <= (others => '0');
  mgt_txd(1) <= (others => '0');
  mgt_txd(2) <= (others => '0');
  mgt_txd(3) <= (others => '0');
  mgt_txk <= (others => '0');

end architecture;
